home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / dev / lang / python_src.lha / amigapython / lib / sched.py < prev    next >
Text File  |  1995-10-22  |  4KB  |  100 lines

  1. # Module sched -- a generally useful event scheduler class
  2.  
  3. # Each instance of this class manages its own queue.
  4. # No multi-threading is implied; you are supposed to hack that
  5. # yourself, or use a single instance per application.
  6. #
  7. # Each instance is parametrized with two functions, one that is
  8. # supposed to return the current time, one that is supposed to
  9. # implement a delay.  You can implement real-time scheduling by
  10. # substituting time and sleep from built-in module time, or you can
  11. # implement simulated time by writing your own functions.  This can
  12. # also be used to integrate scheduling with STDWIN events; the delay
  13. # function is allowed to modify the queue.  Time can be expressed as
  14. # integers or floating point numbers, as long as it is consistent.
  15.  
  16. # Events are specified by tuples (time, priority, action, argument).
  17. # As in UNIX, lower priority numbers mean higher priority; in this
  18. # way the queue can be maintained fully sorted.  Execution of the
  19. # event means calling the action function, passing it the argument.
  20. # Remember that in Python, multiple function arguments can be packed
  21. # in a tuple.   The action function may be an instance method so it
  22. # has another way to reference private data (besides global variables).
  23. # Parameterless functions or methods cannot be used, however.
  24.  
  25. # XXX The timefunc and delayfunc should have been defined as methods
  26. # XXX so you can define new kinds of schedulers using subclassing
  27. # XXX instead of having to define a module or class just to hold
  28. # XXX the global state of your particular time and delay functtions.
  29.  
  30. import bisect
  31.  
  32. class scheduler:
  33.     #
  34.     # Initialize a new instance, passing the time and delay functions
  35.     #
  36.     def __init__(self, timefunc, delayfunc):
  37.         self.queue = []
  38.         self.timefunc = timefunc
  39.         self.delayfunc = delayfunc
  40.     #
  41.     # Enter a new event in the queue at an absolute time.
  42.     # Returns an ID for the event which can be used
  43.     # to remove it, if necessary.
  44.     #
  45.     def enterabs(self, time, priority, action, argument):
  46.         event = time, priority, action, argument
  47.         bisect.insort(self.queue, event)
  48.         return event # The ID
  49.     #
  50.     # A variant that specifies the time as a relative time.
  51.     # This is actually the more commonly used interface.
  52.     #
  53.     def enter(self, delay, priority, action, argument):
  54.         time = self.timefunc() + delay
  55.         return self.enterabs(time, priority, action, argument)
  56.     #
  57.     # Remove an event from the queue.
  58.     # This must be presented the ID as returned by enter().
  59.     # If the event is not in the queue, this raises RuntimeError.
  60.     #
  61.     def cancel(self, event):
  62.         self.queue.remove(event)
  63.     #
  64.     # Check whether the queue is empty.
  65.     #
  66.     def empty(self):
  67.         return len(self.queue) == 0
  68.     #
  69.     # Run: execute events until the queue is empty.
  70.     #
  71.     # When there is a positive delay until the first event, the
  72.     # delay function is called and the event is left in the queue;
  73.     # otherwise, the event is removed from the queue and executed
  74.     # (its action function is called, passing it the argument).
  75.     # If the delay function returns prematurely, it is simply
  76.     # restarted.
  77.     #
  78.     # It is legal for both the delay function and the action
  79.     # function to to modify the queue or to raise an exception;
  80.     # exceptions are not caught but the scheduler's state
  81.     # remains well-defined so run() may be called again.
  82.     #
  83.     # A questionably hack is added to allow other threads to run:
  84.     # just after an event is executed, a delay of 0 is executed,
  85.     # to avoid monopolizing the CPU when other threads are also
  86.     # runnable.
  87.     #
  88.     def run(self):
  89.         q = self.queue
  90.         while q:
  91.             time, priority, action, argument = q[0]
  92.             now = self.timefunc()
  93.             if now < time:
  94.                 self.delayfunc(time - now)
  95.             else:
  96.                 del q[0]
  97.                 void = apply(action, argument)
  98.                 self.delayfunc(0) # Let other threads run
  99.     #
  100.